/*
 * Created on Feb 19, 2004
 *
 * To change the template for this generated file go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
package ModuleBuilder.UI.tree;

import java.util.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.*;
import javax.swing.*;
import javax.swing.tree.*;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.event.*;

import ModuleBuilder.model.*;
import ModuleBuilder.UI.*;

/**
 * @author Milton  Soong
 *
 * To change the template for this generated type comment go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 * 
 * The Tree Holds a root object by the name of "Game Data". The first level nodes 
 * below this (all of them are immune to deletion:
 * 
 * 1) Description: A text area that the scenario auther can put in whatever designers notes,
 * 		PLayer's notes, FAQ, README information he wants.
 * 
 * 2) Custom Actions: Custom Actions are defined here (i.e. game system specific fire, morale check,
 * 		etc. Each action is associated with ONE template (optional), and ONE button
 * 		that will be added to the control panel (REQUIRED).
 * 
 * 3) Overlay Template: Here is where all the overlay templates are defined (i.e
 * 		fire, front/flank/rear, command, etc.)
 * 
 * 4) Unit Template: Where unit type are defined (i.e attributes and overlay templates are defined 
 * 		here.
 * 
 * 5) OB Roster: Where an instance of a unit is defined. Also images are associated here.
 * 
 * The right side of this panel is a CardLayout of all the editors that's permitted
 * Depending on which node is the current node, the correct editor is shown. 
 *
 * All of these Node Type will implement the iGameTreeNode.  
 */
public class GameTreeEditor  extends JPanel 
						 implements ActionListener, TreeSelectionListener {
	private int newNodeSuffix = 1;
	private static String ADD_COMMAND = "add";
	private static String REMOVE_COMMAND = "remove";
	private static String CLEAR_COMMAND = "clear";
	
	/**
	 * Defines for gameEditor type that really should be in the model
	 */
	public static final String SCENARIO_DETAIL_EDITOR = "SD".intern();

	private static HashMap editorLookup = new HashMap();
	    
	private DynamicTree treePanel;
	private UnitProfileEditor unitProfileEditor;
	private OBEditor obEditor;
	private OverlayTemplateEditor overlayTemplateEditor;
	private CustomActionEditor customActionEditor;
	private JTree tree;
	private CardLayout cl;
	private JPanel allEditorPanel;
	private ScenarioDetailEditor scenarioDetailEditor;
	
	public GameTreeEditor() {
		super(new BorderLayout());
	        
		//Create the components.
		treePanel = new DynamicTree();
		unitProfileEditor = new UnitProfileEditor(this);
		obEditor = new OBEditor(this);
		overlayTemplateEditor = new OverlayTemplateEditor();
		customActionEditor = new CustomActionEditor();
		JPanel blankP = new JPanel();
		scenarioDetailEditor = new ScenarioDetailEditor(this);

		populateTree(treePanel);
		obEditor.populateProfileList();	// have to call this after the tree is populated
		
		// populate the editor name==>Editor object lookup table
		editorLookup.put(GameModel.CUSTOM_ACTION_EDITOR, customActionEditor);
		editorLookup.put(GameModel.OVERLAY_EDITOR, overlayTemplateEditor);
		editorLookup.put(GameModel.UNIT_PROFILE_EDITOR, unitProfileEditor);
		editorLookup.put(GameModel.OB_EDITOR, obEditor);
		editorLookup.put(SCENARIO_DETAIL_EDITOR, scenarioDetailEditor);
	
		JButton addButton = new JButton("Add");
		addButton.setActionCommand(ADD_COMMAND);
		addButton.addActionListener(this);
	        
		JButton removeButton = new JButton("Remove");
		removeButton.setActionCommand(REMOVE_COMMAND);
		removeButton.addActionListener(this);
	        
		JButton clearButton = new JButton("Clear");
		clearButton.setActionCommand(CLEAR_COMMAND);
		clearButton.addActionListener(this);
	
		//Lay everything out.
		treePanel.setPreferredSize(new Dimension(300, 150));
		// add(treePanel, BorderLayout.CENTER);
		add(treePanel, BorderLayout.LINE_START);
	
		JPanel panel = new JPanel(new GridLayout(0,1));
		panel.add(addButton);
		panel.add(removeButton);
		panel.add(clearButton);
		
		// Add a panel on the Right with Card Layout, and then
		allEditorPanel = new JPanel();
		cl = new CardLayout();
		allEditorPanel.setLayout(cl);
		
		allEditorPanel.add(overlayTemplateEditor, GameModel.OVERLAY_EDITOR );
		allEditorPanel.add(customActionEditor, GameModel.CUSTOM_ACTION_EDITOR );
		allEditorPanel.add(unitProfileEditor, GameModel.UNIT_PROFILE_EDITOR );
		allEditorPanel.add(obEditor, GameModel.OB_EDITOR );
		allEditorPanel.add(scenarioDetailEditor, SCENARIO_DETAIL_EDITOR );
		allEditorPanel.add(blankP, GameModel.NO_EDITOR);
		
		cl.show(allEditorPanel, GameModel.NO_EDITOR);
		add(allEditorPanel, BorderLayout.CENTER);
		// this.add(unitProfileEditor, BorderLayout.CENTER);
		
		// setup node selection listener
		tree = treePanel.getTree();
		tree.getSelectionModel().setSelectionMode(TreeSelectionModel.SINGLE_TREE_SELECTION);
		tree.addTreeSelectionListener(this);
	}
	
	public static iEditorPanel lookupEditorPanel( String name ) {
		return ( (iEditorPanel)editorLookup.get(name));
	}
	
	public void populateTree(DynamicTree treePanel) {
		DefaultMutableTreeNode p1, p2, p3, p4, p5;
	
		GameModel overlayNode = new GameModel("Overlay Template Editor", GameModel.OVERLAY_EDITOR, true, overlayTemplateEditor);
		GameModel cusActionNode = new GameModel("Custom Action Editor", GameModel.CUSTOM_ACTION_EDITOR, true, customActionEditor);
		GameModel unitTypeNode = new GameModel("Unit Profile Editor", GameModel.UNIT_PROFILE_EDITOR, true, unitProfileEditor);
		GameModel obNode = new GameModel("OB Editor", GameModel.OB_EDITOR, true, obEditor);
		
		// for mainNode that also contains data, need to use subclass and with isMain set to false???
		GameModel sdNode = new ScenarioDetailModel("Scenario Detail Editor", SCENARIO_DETAIL_EDITOR, false, scenarioDetailEditor);	
	
		p5 = treePanel.addObject(null, sdNode);
		p1 = treePanel.addObject(null, overlayNode);
		p2 = treePanel.addObject(null, cusActionNode);
		p3 = treePanel.addObject(null, unitTypeNode);
		unitProfileEditor.setEditorNode(p3);
		
		p4 = treePanel.addObject(null, obNode);
	}
	    
    /**
     * One of the edior has just created a new node and is calling you back, need to update 
     * this node with the new data
     * If this is called, then by definition the currently selection is one of the main editor node
     * 
     * @param node the new node to be created.
     */
    public DefaultMutableTreeNode nodeCreated( GameModel node ) {
    	DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
		return (treePanel.addObject(parentNode, node));
    }
    
    public DefaultMutableTreeNode siblingNodeCreated( GameModel node ) {
		DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
		return (treePanel.addSiblingObject(parentNode, node, true ));
    }
    
	public void reloadTreeModel() {
		treePanel.reload();
	}
	
	public void nodeChanged() {
		DefaultMutableTreeNode parentNode = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
		treePanel.nodeChanged(parentNode);
	}
	
	public void deleteCurrentNode() {
		treePanel.removeCurrentNode();
	}
	
	public DefaultMutableTreeNode getCurrentNode() {
		return (treePanel.getCurrentNode());
	}
	
	public Object[] getProfileList() {
		return (unitProfileEditor.getProfileList());
	}
	
	// object is the node of on the tree
	public void newProfileAdded(Object in) {
		obEditor.newProfileAdded(in);
	}
    
	public void profileDeleted( Object in ) {
		obEditor.profileDeleted(in);
	}
	
	public void figureSideViewAdded(ImageElement img) {
		obEditor.figureSideViewAdded(img);		
	}
	
	public void figureTopViewAdded( ImageElement img) {
		obEditor.figureTopViewAdded(img);	
	}
	
	public void actionPerformed(ActionEvent e) {
		String command = e.getActionCommand();
	        
		if (ADD_COMMAND.equals(command)) {
			//Add button clicked
			treePanel.addObject("New Node " + newNodeSuffix++);
		} else if (REMOVE_COMMAND.equals(command)) {
			//Remove button clicked
			treePanel.removeCurrentNode();
		} else if (CLEAR_COMMAND.equals(command)) {
			//Clear button clicked.
			treePanel.clear();
		}
	}
	
	public void valueChanged( TreeSelectionEvent e) {
		DefaultMutableTreeNode node = (DefaultMutableTreeNode)tree.getLastSelectedPathComponent();
		if (node == null) {
			return;
		}
		Object rawNode = node.getUserObject();
		String editorName=GameModel.NO_EDITOR;
		if (rawNode instanceof GameModel ) {
			GameModel nodeInfo = (GameModel)rawNode;
		
			editorName = nodeInfo.getEditorName();
			boolean isNew = nodeInfo.isMainEditor();
			iEditorPanel ed = nodeInfo.getEditor();
		
			if ( isNew ) {
				ed.setModel(null);
			} else {
				ed.setModel(nodeInfo);
			}
			//Debug.out("About to show editorName=" + editorName);
		}
		cl.show(allEditorPanel, editorName);
	}
	
	/**
	 * First give ea unit a unit UnitId (starts from 1), and then return it
	 * @return
	 */
	public DefaultMutableTreeNode store() {
		DefaultMutableTreeNode root = treePanel.getTreeRoot();
		DefaultMutableTreeNode obNode = Util.findOBNode(root);
		Enumeration e = obNode.breadthFirstEnumeration();
		while ( e.hasMoreElements() ){
			DefaultMutableTreeNode currNode = (DefaultMutableTreeNode)e.nextElement();
			GameModel currUserObj = (GameModel)currNode.getUserObject();
			if ( currUserObj.isMainEditor()){
				continue;
			}
			UnitModel currUnit = (UnitModel)currUserObj;
			currUnit.setId();
		}
		return(root);
	}
	
	/**
	 * 1) go through the editor field of ea node and fill it in
	 * 2) create a tree based on the root node
	 * 
	 * @param root
	 */
	public void load(DefaultMutableTreeNode root) {
		// get every child node of the root, 
		// check to see if it's subclass of GameModel 
		// if so then fill in the editor name
		//
		Enumeration e = root.breadthFirstEnumeration();
		while( e.hasMoreElements()) {
			DefaultMutableTreeNode currNode = (DefaultMutableTreeNode)e.nextElement();
			Object userObject = currNode.getUserObject();
			if ( userObject instanceof GameModel ) {
				// this is a node that we need the editor field populated
				GameModel gameNode = (GameModel)userObject;
				gameNode.setEditorFromName();
			}
		}
		
		// Certain other runtime relationship needs to be build:
		// 1. for every unit profile in existence, must call newProfileAdded()
		//
		e = root.children();
		DefaultMutableTreeNode currNode=null;
		while( e.hasMoreElements()){
			currNode = (DefaultMutableTreeNode)e.nextElement();
			Object currMod = currNode.getUserObject();
			if ( currMod instanceof GameModel ){
				GameModel gameMod = (GameModel)currMod;
				if ( gameMod.getEditorName().equals(GameModel.UNIT_PROFILE_EDITOR)){
					break;
				}			
			}				
		}
		// now currNode contains the unitProfile node
		unitProfileEditor.setEditorNode(currNode);
		obEditor.populateProfileList();
		
		/**
		 * Now because the model might come up with different nodes, instead of blindly setting 
		 * the nodes, we need to iterate over the new loaded tree nodes, and then replace it 
		 * against the existing nodes
		 * 1. iterate over the old roots and then create a lookup table
		 * 2. add/replace new nodes onto the old root
		 */
		DefaultMutableTreeNode oldRoot = treePanel.getTreeRoot();
		HashMap newNodeHash = setupOldRootNodeHash(root);
		
		e = oldRoot.children();
		currNode=null;
		int childIndex=0;
		
		// now loop through the new nodes, and then try to find a old node equivalent.
		// if found, replace, if not found, then add
		//
		while( e.hasMoreElements()){
			currNode = (DefaultMutableTreeNode)e.nextElement();
			Object currMod = currNode.getUserObject();
			if ( currMod instanceof GameModel ){
				GameModel gameMod = (GameModel)currMod;
				String newNodeName = gameMod.getName();
				DefaultMutableTreeNode correspondingNewNode = (DefaultMutableTreeNode)newNodeHash.get(newNodeName);
				if ( correspondingNewNode == null ){
					// this node does not exist in the old world, need to add it to the new
					treePanel.insertObject(root, currMod, true, childIndex);
					
				} else {
					// this node is already existing in the old world, do nothing
				}
			}
			childIndex++;
		}	
		treePanel.setTreeRoot(root);
		return;
	}
	
	/**
	 * 
	 * @param oldRoot
	 * @return HashMap where the key is the name of the node, and the val is the node itself
	 */
	private HashMap setupOldRootNodeHash(DefaultMutableTreeNode oldRoot) {
		HashMap h = new HashMap();
		Enumeration e = oldRoot.children();
		DefaultMutableTreeNode currNode=null;
		while( e.hasMoreElements()){
			currNode = (DefaultMutableTreeNode)e.nextElement();
			Object currMod = currNode.getUserObject();
			if ( currMod instanceof GameModel ){
				GameModel gameMod = (GameModel)currMod;
				String nodeName = gameMod.getName();
				h.put(nodeName, currNode);
			}
		}
		return ( h );
	}
}
